#!/bin/bash
set -e

# Command line flags used for 'docker compose build'
DOCKER_COMPOSE_BUILD_OPTS=${DOCKER_COMPOSE_BUILD_OPTS-"--parallel"}

# Enable buildkit support locally
if [ -z $CI ]; then
  export COMPOSE_DOCKER_CLI_BUILD=1
  export DOCKER_BUILDKIT=1
fi

# Export Explorer docker tag to be used in docker-compose files
if [ -z $EXPLORER_DOCKER_TAG ]; then
  export EXPLORER_DOCKER_TAG="develop"
fi

base_files="-f docker-compose.yaml -f docker-compose.postgres.yaml"
# Allow for choosing between geth or parity
if [ $GETH_MODE ]; then
  base_files="$base_files -f docker-compose.gethnet.yaml"
else
  base_files="$base_files -f docker-compose.paritynet.yaml"
fi

# Build Explorer from source if path is set
if [ $EXPLORER_SOURCE_PATH ]; then
  base_files="$base_files -f docker-compose.explorer-source.yaml"
else
  base_files="$base_files -f docker-compose.explorer.yaml"
fi

base="docker-compose $base_files"                                       # base config, used standalone for acceptance
dev="$base -f docker-compose.dev.yaml"                                  # config for cldev
test="$base -f docker-compose.integration.yaml"                         # config to run integration tests
ts_test="$base -f docker-compose.ts-integration.yaml"                   # config to run integration tests in typescript
deps="$test -f docker-compose.deps.yaml"                                # config to bring up integration test dependencies
dev_integration="$test -f docker-compose.dev-integration.yaml"          # config to run integration tests in dev mode
dev_ts_integration="$ts_test -f docker-compose.dev-ts-integration.yaml" # config to run integration tests in dev mode

clean_docker() {
  $base down -v --remove-orphans
  $dev down -v --remove-orphans
  $test down -v --remove-orphans
  $deps down -v --remove-orphans
  $dev_integration down -v --remove-orphans
  $ts_test down -v --remove-orphans
}

function save_test_logs() {
  mkdir -p logs
  $ts_test logs --no-color node &>./logs/node.log
  $ts_test logs --no-color node-2 &>./logs/node-2.log
  $ts_test logs --no-color devnet &>./logs/devnet.log
  $ts_test logs --no-color node-db &>./logs/node-db.log
  $ts_test logs --no-color node-db-2 &>./logs/node-db-2.log
  $ts_test logs --no-color explorer &>./logs/explorer.log
  $ts_test logs --no-color explorer-db &>./logs/explorer-db.log
  $ts_test logs --no-color external-adapter &>./logs/external-adapter.log
  $test logs --no-color cypress-job-server &>./logs/cypress-job-server.log
  $test logs --no-color echo-server &>./logs/echo-server.log
}

usage="compose -- A helper script for running common docker-compose commands\

Commands:
    help                  Displays this help menu
    clean                 Remove any containers and volumes related to compose files
    logs                  Display the logs of any service(s) by name

    cld                   Runs the chainlink node container in dev mode
    cldo                  cld in addition to operator-ui in dev mode

    acceptance            Run the services required to perform an acceptance test

    test                  Run integration test suite
    test:down             Cleanup resources that may have been left over by ./compose test, used for CI
    test:dev              Run integration test suite with /tools/ci/ethereum_test and /integration bind-mounted
    test:ts               Run integration test suite in typescript (WIP)
    test:ts:down          Cleanup resources that may have been left over by ./compose test:ts, used for CI
    test:ts:dev           Run integration test suite with /tools/ci-ts bind-mounted (WIP)

    integration | i       Run docker-compose with config for integration tests
    dev:integration | di  Run docker-compose with dev config for integration tests
    dev                   Run docker-compose with dev config for the core node and operator-ui

    eth:restart             Reset blockchain data to genesis state
    cl:restart              Reset chainlink database

    *                     Run docker-compose with base config"

case "$1" in
help)
  echo "$usage"
  ;;
clean)
  clean_docker
  ;;
logs)
  $base logs -f ${@:2}
  ;;
logs:test:save)
  save_test_logs
  ;;
cld)
  $dev build
  $dev up -d node
  docker exec -it chainlink-node bash
  $dev down -v --remove-orphans
  ;;
cldo)
  $dev build
  $dev up -d operator-ui
  docker exec -it chainlink-node bash
  $dev down -v --remove-orphans
  ;;

acceptance)
  $base build $DOCKER_COMPOSE_BUILD_OPTS
  $base up
  ;;

test)
  $test build $DOCKER_COMPOSE_BUILD_OPTS
  $deps up --exit-code-from wait-db wait-db
  $test up --exit-code-from integration
  save_test_logs
  $test down -v --remove-orphans
  ;;
test:down)
  $test down -v --remove-orphans
  ;;
test:dev)
  $deps up --exit-code-from wait-db wait-db
  $dev_integration up --exit-code-from integration
  $dev_integration down -v --remove-orphans
  ;;
test:ts)
  $ts_test build $DOCKER_COMPOSE_BUILD_OPTS
  $deps up --exit-code-from wait-db wait-db
  $deps up --exit-code-from wait-db-2 wait-db-2
  set +e

  # Avoiding hanging, because of a bug: https://github.com/docker/compose/issues/3106
  export COMPOSE_INTERACTIVE_NO_CLI=1

  $ts_test run integration-ts /bin/sh -c \
    "docker cp chainlink-node:/usr/local/bin/chainlink /usr/local/bin/chainlink \
      && yarn workspace @chainlink/ci-ts test --runInBand ${@:2}"
  exit_code=$?
  set -e
  save_test_logs
  $ts_test down -v --remove-orphans
  exit $exit_code
  ;;
test:ts:down)
  $ts_test down -v --remove-orphans
  ;;
test:ts:dev)
  $deps up --exit-code-from wait-db wait-db
  $deps up --exit-code-from wait-db-2 wait-db-2
  set +e
  $dev_ts_integration run integration-ts /bin/sh -c \
    "docker cp chainlink-node:/usr/local/bin/chainlink /usr/local/bin/chainlink \
      && yarn workspace @chainlink/ci-ts test --verbose --runInBand ${@:2}"
  exit_code=$?
  set -e
  save_test_logs
  $dev_ts_integration down -v --remove-orphans
  exit $exit_code
  ;;
integration | i)
  $test ${@:2}
  ;;
dev:integ | di)
  $dev_integration ${@:2}
  ;;
dev)
  $dev ${@:2}
  ;;

eth:restart)
  $base rm --force --stop devnet
  if [ $GETH_MODE ]; then
    docker volume rm --force docker_geth-db-data
  else
    docker volume rm --force docker_parity-db-data
  fi
  $base up -d devnet
  ;;
cl:restart)
  $base stop node
  $base rm --force --stop node-db
  docker volume rm --force docker_node-db-data
  ./compose eth:restart
  $deps up --exit-code-from wait-db wait-db
  $base start node
  ;;
*)
  $base $@
  ;;
esac
